﻿
#If RETIRED Then
Imports std

Public Module _strsepar
    'this is a little quick than the one with surroundStr
    Private Function strseparImpl(Of T)(ByVal str As String, ByVal separators As String, ByVal result As T, _
                                        ByVal insert As insertDelegate(Of T, String), _
                                        ByVal ignoreEmptyEntity As Boolean) As T
        If Not isemptystring(str) Then
            assert(Not result Is Nothing, "result is nothing.")
            assert(Not insert Is Nothing, "insert is nothing.")

            If isemptystring(separators) Then
                insert(result, str)
            Else
                Dim i As Int32
                Dim last As Int32
                Dim len As Int32
                Dim nextChar As Int32
                Dim minNext As Int32
                Dim seplen As Int32

                last = 0
                len = strlen(str)
                seplen = strlen(separators)
                While last <= len
                    minNext = len
                    For i = 0 To seplen - 1
                        nextChar = str.IndexOf(separators(i), last)
                        If nextChar < minNext AndAlso nextChar <> npos Then
                            minNext = nextChar
                        End If
                    Next

                    If (Not ignoreEmptyEntity OrElse minNext - last > 0) Then
                        insert(result, strmid(str, last, minNext - last))
                    End If
                    last = minNext + 1
                End While
            End If
        End If

        Return result
    End Function

    Private Function strseparImpl(Of T)(ByVal str As String, ByVal separators As String, ByRef result As T, _
                                        ByVal surroundStr As String, ByVal insert As insertDelegate(Of T, String), _
                                        Optional ByVal ignoreEmptyEntity As Boolean = False, _
                                        Optional ByVal ignoreSurroundChar As Boolean = True) As T
        If isemptystring(surroundStr) OrElse isemptystring(separators) Then
            strseparImpl(str, separators, result, insert, ignoreEmptyEntity)
        Else
            assert(Not result Is Nothing, "result is nothing.")
            assert(Not insert Is Nothing, "inserter is nothing.")

            Dim i As Int32
            Dim last As Int32
            Dim len As Int32
            Dim surrounding As Boolean

            len = strlen(str)
            last = 0
            surrounding = False
            For i = 0 To len - 1
                If surroundStr.IndexOf(str(i)) <> npos Then
                    surrounding = Not surrounding
                    If Not surrounding Then
                        If ignoreSurroundChar Then
                            If Not ignoreEmptyEntity OrElse last < i Then
                                insert(result, strmid(str, last, i - last))
                            End If
                        Else
                            If Not ignoreEmptyEntity OrElse last < i - 1 Then
                                insert(result, strmid(str, last, i - last + 1))
                            End If
                        End If
                        'if next of a surroundStr is separator, jump to next
                        If i < len - 1 AndAlso separators.IndexOf(str(i + 1)) <> npos Then
                            i += 1
                        End If
                        last = i + 1
                    Else
                        If ignoreSurroundChar Then
                            last = i + 1
                        Else
                            last = i
                        End If
                    End If
                ElseIf Not surrounding AndAlso separators.IndexOf(str(i)) <> npos Then
#If RETIRED Then
                        AndAlso (i = 0 OrElse surroundStr.IndexOf(str(i - 1)) = npos) Then
                    If Not ignoreEmptyEntity OrElse ((ignoreSurroundChar AndAlso last < i) _
                                                    OrElse (Not ignoreSurroundChar AndAlso last < i - 1)) Then
#End If
                    If Not ignoreEmptyEntity OrElse last < i Then
                        insert(result, strmid(str, last, i - last))
                    End If
                    last = i + 1
                End If
            Next

            If last < i Then
                insert(result, strmid(str, last, i - last))
            End If
        End If

        Return result
    End Function

    Public Function strsepar(ByVal str As String, ByVal seperators As String, ByRef result As vector(Of String), _
                             ByVal surroundStr As String, Optional ByVal ignoreEmptyEntity As Boolean = False, _
                             Optional ByVal ignoreSurroundChar As Boolean = True) As vector(Of String)
        If result Is Nothing Then
            result = New vector(Of String)()
        Else
            result.clear()
        End If

        Return strseparImpl(str, seperators, result, surroundStr, AddressOf vectorInsert, _
                            ignoreEmptyEntity, ignoreSurroundChar)
    End Function

    Public Function strsepar(ByVal str As String, ByVal seperators As String, ByRef result As vector(Of String), _
                             Optional ByVal ignoreEmptyEntity As Boolean = False) As vector(Of String)
        If result Is Nothing Then
            result = New vector(Of String)()
        Else
            result.clear()
        End If

        Return strseparImpl(str, seperators, result, AddressOf vectorInsert, ignoreEmptyEntity)
    End Function

    Public Function strsepar(ByVal str As String, ByVal seperators As String, ByRef result As [set](Of String), _
                             Optional ByVal ignoreEmptyEntity As Boolean = False) As [set](Of String)
        If result Is Nothing Then
            result = New [set](Of String)
        Else
            result.clear()
        End If

        Return strseparImpl(str, seperators, result, AddressOf setInsert, ignoreEmptyEntity)
    End Function

    Public Function strsepar(ByVal str As String, ByVal seperators As String, ByRef result As list(Of String), _
                             Optional ByVal ignoreEmptyEntity As Boolean = False) As list(Of String)
        If result Is Nothing Then
            result = New list(Of String)()
        Else
            result.clear()
        End If

        Return strseparImpl(str, seperators, result, AddressOf listInsert, ignoreEmptyEntity)
    End Function
End Module
#End If
